#include "TabsAndToolboxWidget.h"

TabsAndToolboxWidget::TabsAndToolboxWidget()
{
    //Output(message, "Breakpoint");
    setWindowTitle( tr( "Stock program" ) );

    //setLocale( QLocale( QLocale::Russian, QLocale::RussianFederation ) );

    dbms = new DBMS();
    //dbms->RestoreDefaultDatabases();
    //dbms->ChangeDatabaseInfo();
    //return;
    dbms->ConnectDatabase( "Materials" );
    dbms->ConnectDatabase( "Furniture" );
    dbms->ConnectDatabase( "Profile" );
    dbms->ConnectDatabase( "Stock" );
    dbms->ConnectDatabase( "Orders" );
    dbms->ConnectDatabase( "Income" );

    DB_Furniture = dbms->GetDatabase( "Furniture" );
    DB_Profile   = dbms->GetDatabase( "Profile" );
    DB_Materials = dbms->GetDatabase( "Materials" );
    DB_Stock     = dbms->GetDatabase( "Stock" );
    DB_Orders    = dbms->GetDatabase( "Orders");
    DB_Income    = dbms->GetDatabase( "Income");

    Furniture = new StockTableView( DB_Furniture, this );
    Profile   = new StockTableView( DB_Profile, this );
    Orders    = new StockTableView( DB_Orders, this );
    Income    = new StockTableView( DB_Income, this );
    Stock     = new StockTableView( DB_Stock, this );
    //Output(message, "Breakpoint");

    //Orders->setSortingEnabled( true );
    //Orders->sortByColumn(3, Qt::DescendingOrder );
    Orders->setFirstColumnSorting( true );

    //conecting all "*_w" databases
    OrderItem itemForWantageIndex;
    for (int i=0; i<DB_Orders->GetItemsCount(); i++ ){
        DB_Orders->GetItem( i, itemForWantageIndex );
        dbms->ConnectDatabase( itemForWantageIndex.GetDatabase() + "_w" );
    }

    /*DataBaseInfo DBInfo;
    DBInfo.DBName = "temp";
    DBInfo.ItemsNumber = 0;
    DBInfo.KeyField = 0;
    DBInfo.RecordsNumber = 1;
    DBInfo.VisibleNumber = 1;

    dbms->CreateDatabase( DBInfo );
    dbms->GetDatabase(
    return;
    */

    //Making ItemEditDialog

    QVector<QString> headers;
    int fieldNumber = DB_Stock->GetFieldNumber();
    int keyField = DB_Stock->GetKeyField();
    ( DB_Stock )->GetColumnHeaderVector( headers );

    itemEditDialog = new ItemEditDlg( headers, fieldNumber, keyField, this );

    fillUpDialog = new DatabaseFillUpDialog( dbms, this );

    //Making Tabs
    Tabs = new QTabWidget();
    Tabs->addTab( Orders, tr("Orders") );
    Tabs->addTab( Income, tr("Income") );
    Tabs->addTab( Stock, tr("Stock") );
    Tabs->addTab( Furniture, tr("Furniture") );
    Tabs->addTab( Profile, tr("Profile") );


    orderButtons = new OrderButtonsWidget();
    incomeButtons = new IncomeButtonsWidget();
    stockButtons = new StockButtonsWidget();

    ToolBox = new QToolBox();
    ToolBox->addItem( orderButtons, tr("Orders") );
    ToolBox->addItem( incomeButtons, tr("Income") );
    ToolBox->addItem( stockButtons, tr("Stock") );
    ToolBox->setFixedWidth( 200 );
    ToolBox->setFixedHeight( 400 );

    ToolBoxLayout = new QVBoxLayout();
    ToolBoxLayout->addWidget( ToolBox );
    ToolBoxLayout->addStretch();

    // Managing MainLayout
    MainLayout = new QHBoxLayout();
    MainLayout->addWidget( Tabs );
    MainLayout->addLayout( ToolBoxLayout );

    setLayout( MainLayout );

    PrintDB = new PrintDatabase();

    // Signals and Slots
    //connect( ToolBox, SIGNAL(currentChanged(int)), Tabs, SLOT(setCurrentIndex(int)) );
    //connect( Tabs, SIGNAL(currentChanged(int)), ToolBox, SLOT(setCurrentIndex(int)) );
    connect( ToolBox, SIGNAL(currentChanged(int)), this, SLOT(ToolChanged(int)) );
    connect( Tabs, SIGNAL(currentChanged(int)), this, SLOT(TabChanged(int)) );

    connect( orderButtons->GetButton( 0 ), SIGNAL(clicked()), this, SLOT(NewOrderPressed()) );
    connect( orderButtons->GetButton( 1 ), SIGNAL(clicked()), this, SLOT(RemoveOrderPressed()) );
    connect( orderButtons->GetButton( 2 ), SIGNAL(clicked()), this, SLOT(EditOrderPressed()) );
    connect( orderButtons->GetButton( 3 ), SIGNAL(clicked()), this, SLOT(PauseOrderPressed()) );
    connect( orderButtons->GetButton( 4 ), SIGNAL(clicked()), this, SLOT(ResumeOrderPressed()) );
    connect( orderButtons->GetButton( 5 ), SIGNAL(clicked()), this, SLOT(PrintWantagePressed()) );

    connect( incomeButtons->GetButton( 0 ), SIGNAL(clicked()), this, SLOT(NewIncomePressed()) );
    connect( incomeButtons->GetButton( 1 ), SIGNAL(clicked()), this, SLOT(RemoveIncomePressed()) );
    connect( incomeButtons->GetButton( 2 ), SIGNAL(clicked()), this, SLOT(EditIncomePressed()) );
    connect( incomeButtons->GetButton( 3 ), SIGNAL(clicked()), this, SLOT(PauseIncomePressed()) );
    connect( incomeButtons->GetButton( 4 ), SIGNAL(clicked()), this, SLOT(ResumeIncomePressed()) );

    //Stock buttons
    connect( stockButtons->GetButton( 0 ), SIGNAL(clicked()), this, SLOT(AddItemPressed()) );
    connect( stockButtons->GetButton( 1 ), SIGNAL(clicked()), this, SLOT(EditItemPressed()) );
    connect( stockButtons->GetButton( 2 ), SIGNAL(clicked()), this, SLOT(RemoveItemPressed()) );
    connect( stockButtons->GetButton( 3 ), SIGNAL(clicked()), this, SLOT(PrintDatabasePressed()) );
    
    connect( itemEditDialog, SIGNAL(ItemMade(ItemType)), this, SLOT(GetItem(ItemType)) );

    connect( fillUpDialog, SIGNAL(ChangesMade(QMap<QString,int>)), this, SLOT(AcceptOperation(QMap<QString,int>)) );
}

TabsAndToolboxWidget::~TabsAndToolboxWidget()
{
    //delete ToolBoxLayout;     //deletes ToolBox
    delete Tabs;              //deletes all StockTableView
    delete ToolBox;         //deletes all order-, ... buttons
    delete MainLayout;

    //delete DB_Orders;
    //delete DB_Income;
    //delete DB_Stock;
    //delete DB_Furniture;
    //delete DB_Profile;
    //delete DB_Materials;

    //delete Orders;
    //delete Income;
    //delete Stock;
    //delete Furniture;
    //delete Profile;

    delete dbms;

    //delete orderButtons;
    //delete incomeButtons;
    //delete stockButtons;

    delete fillUpDialog;
    delete itemEditDialog;
}

void TabsAndToolboxWidget::TabChanged( int index )
{
    //if ( index > 2 && ToolBox->currentIndex() != 2 ) ToolBox->setCurrentIndex( 2 ); else
    //    if ( ToolBox->currentIndex() != index ) ToolBox->setCurrentIndex( index );
    if ( index > 1 ) ToolBox->setCurrentIndex( 2 ); else ToolBox->setCurrentIndex( index );

    switch ( index ){
        case 0:
            LastDatabase = DB_Orders;
            LastTable = Orders;
            break;
        case 1:
            LastDatabase = DB_Income;
            LastTable = Income;
            break;
        case 2:
            LastDatabase = DB_Stock;
            LastTable = Stock;
            break;
        case 3:
            LastDatabase = DB_Furniture;
            LastTable = Furniture;
            break;
        case 4:
            LastDatabase = DB_Profile;
            LastTable = Profile;
            break;
    }
}

void TabsAndToolboxWidget::ToolChanged( int index )
{
    //if ( Tabs->currentIndex() < 2 )
    //    Tabs->setCurrentIndex( index );
    if ( index < 2 ) Tabs->setCurrentIndex( index ); else
    {
        if ( Tabs->currentIndex() < 2 ) Tabs->setCurrentIndex( 2 );
    }
}

//******************************************************************************//
//**************************** ORDER BUTTONS ***********************************//

void TabsAndToolboxWidget::NewOrderPressed()
{
    LastOperation = 1;
    AddOperation();
}

void TabsAndToolboxWidget::EditOrderPressed()
{
    LastOperation = 1;
    EditOperation();
}

void TabsAndToolboxWidget::RemoveOrderPressed()
{
    LastOperation = 1;
    RemoveOperation();
}

void TabsAndToolboxWidget::PauseOrderPressed()
{
    LastStatus = 2;
    LastOperation = 1;
    ResumePauseOperation();
}

void TabsAndToolboxWidget::ResumeOrderPressed()
{
    LastStatus = 1;
    LastOperation = 1;
    ResumePauseOperation();
}

void TabsAndToolboxWidget::PrintWantagePressed()
{
    OrderItem item;
    PrintDatabase PD;

    switch ( Orders->GetSelectedItem( item ) ){
        case 1:
                //means no row is selected
                Output( warning, tr("No %1 is selected").arg(tr("Order")) );
                break;
        case 0:
                PD.setDB( dbms->GetDatabase( item.GetDatabase() + "_w" ) );
                PD.Print();
                break;
    }
}

//**************************** ORDER BUTTONS ***********************************//
//******************************************************************************//

//******************************************************************************//
//**************************** INCOME BUTTONS **********************************//

void TabsAndToolboxWidget::NewIncomePressed()
{
    LastOperation = 0;
    AddOperation();
}

void TabsAndToolboxWidget::EditIncomePressed()
{
    LastOperation = 0;
    EditOperation();
}

void TabsAndToolboxWidget::RemoveIncomePressed()
{
    LastOperation = 0;
    RemoveOperation();
}

void TabsAndToolboxWidget::PauseIncomePressed()
{
    LastStatus = 2;
    LastOperation = 2;
    ResumePauseOperation();
}

void TabsAndToolboxWidget::ResumeIncomePressed()
{
    LastStatus = 1;
    LastOperation = 2;
    ResumePauseOperation();
}

//**************************** INCOME BUTTONS **********************************//
//******************************************************************************//



//******************************************************************************//
//**************************** STOCK BUTTONS ***********************************//
void TabsAndToolboxWidget::AddItemPressed()
{
    LastPressed = addItem;

    itemEditDialog->SetItem( ItemType( LastDatabase->GetFieldNumber() ) );
    itemEditDialog->exec();
}

void TabsAndToolboxWidget::EditItemPressed()
{
    LastPressed = editItem;

    ItemType item(LastDatabase->GetFieldNumber());
    switch( LastTable->GetSelectedItem( item ) ){
        case 1:
                //means no row is selected
                Output( warning, tr("No item is selected") );
                break;
        case 0:
                //item was succesfully read from DB
                itemEditDialog->SetItem( item );
                itemEditDialog->exec();
                break;
    }
}

void TabsAndToolboxWidget::GetItem( const ItemType& item )
{
    if ( LastPressed == addItem )
        AddItemToMaterials( item ); else
            EditItemFromMaterials( item );
}

int TabsAndToolboxWidget::AddItemToMaterials( const ItemType& item )
{
    switch( DB_Materials->InsertItem( item ) ){
                case dup_error:
                        Output( warning,
                                tr("Item with %1: %2 already exists in database").arg(
                                        DB_Materials->GetColumnHeader( DB_Materials->GetKeyField() ),
                                        item.Get( DB_Materials->GetKeyField() ) ) );
                                //tr("Item with ") + DB_Materials->GetColumnHeader( DB_Materials->GetKeyField() )
                                //+QString(": ") + item.Get( DB_Materials->GetKeyField() ) +
                                //tr(" already exists in database") );
                        return dup_error;
                        break;
                case ok:
                        //Output( message, tr("Item was succesfully inserted") );
                        emit itemEditDialog->close();
                        break;
        }

    LastDatabase->InsertItem( item );

    return ok;
}

int TabsAndToolboxWidget::EditItemFromMaterials( const ItemType& item )
{
    switch ( DB_Materials->EditItem( item ) ){
        case find_error:
                //means user has changed an article
                //because in other way ok result should be returned
                //new article is already exists in DB
                //Output( warning, tr("Item with Article: ") + item.GetArticle() + tr(" already exists in database") );
                return find_error;
                break;
        case ok:
                //Output( message, tr("Item was succesfully edited") );
                emit itemEditDialog->close();
                //return ok;
                break;
    }

    LastDatabase->EditItem( item );
}

int TabsAndToolboxWidget::RemoveItemPressed()
{

    ItemType item(LastDatabase->GetFieldNumber());
    switch( LastTable->GetSelectedItem( item ) ){
        case 1:
                //means no row is selected
                Output( warning, tr("No item is selected") );
                break;
        case 0:
                //in item we have real stock item from database
                //no need to check for result of RemoveItem()
                if ( Output( ask, tr("Do you really want to delete this item?") ) == QMessageBox::Cancel) break;
                LastDatabase->RemoveItem( item );
                DB_Materials->RemoveItem( item );
                //Output( message, tr("Item was succesfully removed") );
                break;
    }
}

void TabsAndToolboxWidget::PrintDatabasePressed()
{
    PrintDB->setDB( LastDatabase );
    PrintDB->Print();
}

//**************************** STOCK BUTTONS ***********************************//
//******************************************************************************//

//******************************************************************************//
//************************* OPERATION FUNCTIONS ********************************//

void TabsAndToolboxWidget::AddOperation()
{
    DataBase *current_DB;
    QString current_operation;

    if ( LastOperation == 1 ) {
        current_DB = DB_Orders;
        current_operation = tr("Order");
    } else {
        current_DB = DB_Income;
        current_operation = tr("Income");
    }

    bool ok;
    OperationItem item;
    QString descr = QInputDialog::getText( this, tr("Input"), tr("%1 name:").arg(current_operation),
                                           QLineEdit::Normal, QString(), &ok );

    if (ok && !descr.isEmpty())
        item.SetDescription( descr ); else {
            Output( warning, tr("Can't make database") );
            return;
        }

    //Create database with name descr
    DataBaseInfo DBInfo;

    DBInfo.ColumnHeaders.push_back( tr("Article") );
    DBInfo.ColumnHeaders.push_back( tr("Description") );
    DBInfo.ColumnHeaders.push_back( tr("Number") );
    DBInfo.ColumnHeaders.push_back( tr("Format") );

    DBInfo.DBName = descr;
    DBInfo.ItemsNumber = 0;
    DBInfo.KeyField = 0;
    DBInfo.RecordsNumber = 4;
    DBInfo.VisibleNumber = 4;

    if ( dbms->CreateDatabase( DBInfo ) == dup_error ){
        Output( message,  tr("%1: %2 already exists").arg(current_operation, descr) );
        return;
    }

    //creating database descr + "_w", wantage will be stored there
    if ( LastOperation == 1 ) {
        DBInfo.DBName = descr + "_w";
        dbms->CreateDatabase( DBInfo );
        dbms->ConnectDatabase( DBInfo.DBName );
    }

    item.SetDatabse( descr );
    item.SetStatus( tr("running") );
    item.SetDateTime( QDateTime::currentDateTime() );

    current_DB->InsertItem( item );
    current_DB->SaveDatabaseToFile();


    dbms->ConnectDatabase( item.GetDatabase() );
    fillUpDialog->SetDatabase( dbms->GetDatabase( item.GetDatabase() ) );
    //Output( message, "Breakpoint" );
    fillUpDialog->exec();

    CheckForWantage( 0, 0 );
}

void TabsAndToolboxWidget::EditOperation()
{
    OperationItem item;
    StockTableView* currentTable;
    QString currentOperation;

    if (LastOperation == 1) {
        currentTable = Orders;
        currentOperation = tr("Order");
    } else {
        currentTable = Income;
        currentOperation = tr("Income");
    }

    switch ( currentTable->GetSelectedItem( item ) ){
        case 1:
                //means no row is selected
                Output( warning, tr("No %1 is selected").arg(currentOperation) );
                break;
        case 0:
                if ( item.GetStatus() == tr("paused") ){
                    Output( message, tr("%1 is paused, please renew it to edit").arg(currentOperation) );
                    break;
                }

                dbms->ConnectDatabase( item.GetDatabase() );
                fillUpDialog->SetDatabase( dbms->GetDatabase( item.GetDatabase() ) );
                //Output( message, "Breakpoint" );
                fillUpDialog->exec();
                //emit
    }
}

void TabsAndToolboxWidget::RemoveOperation()
{
    OperationItem item;
    StockTableView* currentTable;
    QString currentOperation;
    DataBase* currentDB;

    if (LastOperation == 1) {
        currentDB = DB_Orders;
        currentTable = Orders;
        currentOperation = tr("Order");
    } else {
        currentDB = DB_Income;
        currentTable = Income;
        currentOperation = tr("Income");
    }

    bool needToDelete = true;
    StockItem stockItem;
    QMap<QString, int> changes;

    switch ( currentTable->GetSelectedItem( item ) ){
        case 1:
                //means no row is selected
                Output( warning, tr("No %1 is selected").arg(currentOperation) );
                break;
        case 0:
                if ( item.GetStatus() == tr("paused") ) needToDelete = false;

                if ( Output( ask, tr("Do you really want to delete this %1?").arg(currentOperation) )
                    == QMessageBox::Cancel) break;

                if (needToDelete){
                    dbms->ConnectDatabase( item.GetDatabase() );
                    DataBase* db2delete = dbms->GetDatabase( item.GetDatabase() );

                    for (int i=0; i<db2delete->GetItemsCount(); i++){
                        db2delete->GetItem( i, stockItem );
                        changes[ stockItem.GetArticle() ] = -stockItem.GetNumber();
                    }
                    emit this->AcceptOperation( changes );
                }

                currentDB->RemoveItem( item );
                dbms->RemoveDatabase( item.GetDatabase() );
                if (LastOperation == 1) dbms->RemoveDatabase( item.GetDatabase() + "_w" );
                break;
    }
}

void TabsAndToolboxWidget::AcceptOperation( QMap<QString,int> changes )
{   
    int op = 1;

    if ( LastOperation == 1 ) op = -1; else op = 1;

    QMap<QString, int>::const_iterator i;
    StockItem item;

    for ( i = changes.begin(); i != changes.end(); i++ )
        if ( DB_Stock->GetItem( i.key(), item ) != find_error ) {
            item.SetNumber( item.GetNumber() + op * i.value() );
            DB_Stock->EditItem( item );
        } else
            if ( DB_Furniture->GetItem( i.key(), item ) != find_error ){
                item.SetNumber( item.GetNumber() + op * i.value() );
                DB_Furniture->EditItem( item );
            } else
                if ( DB_Profile->GetItem( i.key(), item ) != find_error ){
                    item.SetNumber( item.GetNumber() + op * i.value() );
                    DB_Profile->EditItem( item );
                }

    //fillUpDialog->close();
}

void TabsAndToolboxWidget::ResumePauseOperation()
{
    OperationItem item;
    StockTableView* currentTable;
    QString currentOperation;
    DataBase* currentDB;

     if (LastOperation == 1) {
        currentDB = DB_Orders;
        currentTable = Orders;
        currentOperation = tr("Order");
    } else {
        currentDB = DB_Income;
        currentTable = Income;
        currentOperation = tr("Income");
    }

    int op = 1;
    QString status;

    if ( LastStatus == 1 ){
        op = 1;
        status = tr("running");
    } else {
        op = -1;
        status = tr("paused");
    }

    StockItem stockItem;
    QMap<QString, int> changes;

    switch ( currentTable->GetSelectedItem( item ) ){
        case 1:
                //means no row is selected
                Output( warning, tr("No %1 is selected").arg(currentOperation) );
                break;
        case 0:

                if ( LastStatus == 1 && item.GetStatus() == tr("running") ){
                    Output( message, currentOperation + " is currently " + status );
                    break;
                }

                if ( LastStatus == 2 && item.GetStatus() == tr("paused") ){
                    Output( message, currentOperation + " is currently " + status );
                    break;
                }

                dbms->ConnectDatabase( item.GetDatabase() );
                DataBase* db2ResumePause = dbms->GetDatabase( item.GetDatabase() );

                for (int i=0; i<db2ResumePause->GetItemsCount(); i++){
                    db2ResumePause->GetItem( i, stockItem );
                    changes[ stockItem.GetArticle() ] = op * stockItem.GetNumber();
                }
                emit this->AcceptOperation( changes );

                item.SetStatus( status );
                currentDB->EditItem( item );

                break;
    }
}

//************************* OPERATION FUNCTIONS ********************************//
//******************************************************************************//

void TabsAndToolboxWidget::CheckForWantage(int first, int last)
{
    DataBase *wantageDB;
    DataBase *orderItemsDB;
    OrderItem orderIndexItem;
    StockItem stockIndexItem;
    StockItem materialIndexItem;

    int countOnStock;
    int countFromPrevious = 0;
    int needToTake;

    for (int i=first; i<=last; i++){
        //DB_Orders->GetItem( i, orderIndexItem );
        Orders->getItem( i, orderIndexItem );
        dbms->ConnectDatabase( orderIndexItem.GetDatabase() );
        orderItemsDB = dbms->GetDatabase( orderIndexItem.GetDatabase() );

        for (int j=0; j<orderItemsDB->GetItemsCount(); j++){
            orderItemsDB->GetItem( j, stockIndexItem );
            DB_Materials->GetItem( stockIndexItem.GetArticle(), materialIndexItem );

            countOnStock = materialIndexItem.GetNumber();
            needToTake = stockIndexItem.GetNumber();

            //inserting to stockIndexItem wantage
            if ( countOnStock + countFromPrevious < 0 ){
               //means not enough
               stockIndexItem.SetNumber( qAbs( countOnStock + countFromPrevious ) );
               countFromPrevious += stockIndexItem.GetNumber();
               //inserting item to wantage
               wantageDB = dbms->GetDatabase( orderIndexItem.GetDatabase() + "_w" );
               wantageDB->InsertItem( stockIndexItem );
            }
        }

        wantageDB->SaveDatabaseToFile();
    }
}
